package com.huitone.smspfm.oldclient;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;

import com.bin.common.utils.ArrayUtils;
import com.bin.common.utils.StringUtils;
import com.huitone.smspfm.oldclient.app.AppStaticConfigs;
import com.huitone.smspfm.oldclient.app.SmsSourceType;
import com.huitone.smspfm.oldclient.asclient.ClientMessageHandler;
import com.huitone.smspfm.oldclient.asclient.send.CrossFileMsgSendTask;
import com.huitone.smspfm.oldclient.asclient.send.GenerateMsgSendTask;
import com.huitone.smspfm.oldclient.asclient.send.GenerateMsgSendTaskNew;
import com.huitone.smspfm.oldclient.asclient.send.MsgResendTask;
import com.huitone.smspfm.oldclient.asserver.ServerMessageHandler;
import com.huitone.smspfm.oldclient.asserver.UserValidator;
import com.huitone.smspfm.oldclient.core.DbWriterDispatcher;
import com.huitone.smspfm.oldclient.core.FileWriterDispatcher;
import com.huitone.smspfm.oldclient.core.listener.OutSideCommandsHandler;
import com.huitone.smspfm.oldclient.core.listener.ShareMemoryCommandsListener;
import com.huitone.smspfm.oldclient.logger.ExtLogger;
import com.huitone.smspfm.oldclient.store.MtGroupTmpStore;
import com.huitone.smspfm.oldclient.store.MtTmpStore;
import com.huitone.smspfm.socket.client.SmsClient;
import com.huitone.smspfm.socket.core.net.ExtSocketManager;
import com.huitone.smspfm.socket.server.SmsServer;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * @Title Main.java
 * @Package com.huitone.smspfm.oldclient
 * @Description TODO(用一句话描述该文件做什么)
 * @author ybliang
 * @date 2017年10月12日 下午2:15:32
 * @version V1.0
 */
public class Main {

	static {
		try {
//			String path = Thread.currentThread().getContextClassLoader().getResource("log4j2.xml").getPath().substring(1).replace("/", "\\\\");
//			Configurator.initialize(null, new ConfigurationSource(new FileInputStream(path)));
//			System.setProperty("application.context.file.path","C:\\Users\\ouzai\\Desktop\\config\\applicationContext-file.xml");
			Configurator.initialize(null,new ConfigurationSource(new FileInputStream(System.getProperty("log4j2.xml"))));
		} catch (Exception e) {
			System.out.println("初始化log4j2配置文件错误");
		}
	}
	private final static ExtLogger logger = ExtLogger.create(Main.class);
	private static ShareMemoryCommandsListener listener = null;
	
	private static SmsServer server = null;
	
	private static SmsClient client = null;
	
	private static GenerateMsgSendTaskNew generateMsgSendTaskNew = null;
	private static GenerateMsgSendTask generateMsgSendTask = null;
	
	private static CrossFileMsgSendTask crossFileMsgSendTask = null;
	
	private static MsgResendTask msgResendTask = null;
	
	private static Thread tryStartSendTasks = null;

	public static void main(String[] args) throws Exception {

		// 全局参数初始化
		AppStaticConfigs.init();
		if (args != null && args.length >= 1 && StringUtils.equalsIgnoreCase("test", args[0])) {
			
			if (args.length >= 2) {
				if (StringUtils.equalsIgnoreCase("serverconn", args[1])) {
					testServerConn();
				} else if (StringUtils.equalsIgnoreCase("spextract", args[1])) {
					
					String sendport = null;
					String extractRegex = null;
					int extractIndex = 0;
					
					try {
						sendport = args[2];
						extractRegex = args[3];
					} catch (Exception e) {}
					
					try {
						extractIndex = StringUtils.strToInt(args[4]);
					} catch (Exception e) {}
					
					testSpExtract(sendport, extractRegex, extractIndex);
				}
			}
			
		} else {
			
			// 构建外部命令监听器,监听start,stop,reload等命令
			listener = new ShareMemoryCommandsListener();
			listener.setHandler(new OutSideCommandsHandler() {

				@Override
				public void stop(String[] args) {
					logger.info("stop:" + Arrays.asList(args));
					
					if (ArrayUtils.isEmpty(args)) {
						
						stopService();
						
						stopSendService();
						
						listener.stopListener();
						
					} else {
						
						String param = args[0];
						
						if (StringUtils.equals(param, "lstservice")) {
							stopService();
						} else if (StringUtils.equalsIgnoreCase(param, "sendservice")) {
							stopSendService();
						}
					}
				}

				@Override
				public void start(String[] args) {
					logger.info("start:" + Arrays.asList(args));
					
					if (ArrayUtils.isEmpty(args)) {
						
						//startService();
						
						//startSendService();
						
					} else {
						
						String param = args[0];
						
						if (StringUtils.equalsIgnoreCase(param, "lstservice")) {
							startService();
						} else if (StringUtils.equalsIgnoreCase(param, "sendservice")) {
							startSendService();
						}
					}
				}

				@Override
				public void reload(String[] args) {
					logger.info("reload:" + Arrays.asList(args));
					
					reloadConfigs();
				}

				@Override
				public void handle(String[] args) {
					logger.info("handle:" + Arrays.asList(args));
				}
			});
			
			listener.startListener();
		}
	}
	
	// 测试短信接口是否通
	protected static void testServerConn() {
		
		if (client == null) {
			client = new SmsClient();
			client.setSrvNode(AppStaticConfigs.srvNode);
			client.setServerIp(AppStaticConfigs.serverIp);
			client.setServerPort(AppStaticConfigs.serverPort);
			client.setLoginName(AppStaticConfigs.serverLoginName);
			client.setLoginPass(AppStaticConfigs.serverLoginPass);
			client.setHandlerBound(true);
			client.setMaxSize(AppStaticConfigs.msgSendMaxSize);
		}
		
		if (client.testBindable()) {
			System.out.println("info: Connection successful");
		} else {
			System.out.println("error: Connection fail, please check the logs for more information");
		}
		
		client.destory();
	}
	
	/**
	 * @param sendport 需要提取的源端口号
	 * @param regex 提取正则表达式
	 * @param extractIndex 提取第几组（0 表示匹配到的整个字符串， n 表示用英文括号包裹起来的第几组， 规则是从里到外，从左到右依次数）<br>
	 * 如((95598|10086)(\\d*)) <br>
	 * 1、第0组和第1组是((95598|10086)(\\d*))匹配到的整个字符串 <br>
	 * 2、第2组是匹配到的(95598|10086)字符串 <br>
	 * 3、第3组是匹配到的(\\d*)字符串 <br>
	 */
	protected static void testSpExtract(String sendport, String regex, int extractIndex) {
		String sourceStr = sendport;
		String extractStr = null;
		if (StringUtils.isBlank(sendport)) {
			System.out.println("error: source port " + sourceStr + " is null");
			return;
		}
		if (StringUtils.isBlank(regex)) {
			System.out.println("error: regex " + regex + " is null");
			return;
		}
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(sendport);
		try {
			if (m.find()) {
				extractStr = m.group(extractIndex);
			}
		} catch (Exception e) {
			if (e instanceof IndexOutOfBoundsException) {
				System.out.println("error: extractIndex out of bounds");
			} else {
				logger.error("testSpExtract　 进程异常");
				e.printStackTrace();
			}
		}
		System.out.println("info: source port " + sourceStr + ", result port " + extractStr);
	}

	/**
	 * 关闭短信发送服务
	 */
	protected static void stopSendService() {
		
		if (client != null) {
			client.destory();
			client = null;
		}
		
		if (tryStartSendTasks != null && tryStartSendTasks.isAlive()) {
			tryStartSendTasks.interrupt();
		}
		
		if (generateMsgSendTaskNew != null) {
			generateMsgSendTaskNew.destroy();
			generateMsgSendTaskNew = null;
		}
		
		if (generateMsgSendTask != null){
			generateMsgSendTask.destroy();
			generateMsgSendTask = null;
		}
		
		if (crossFileMsgSendTask != null) {
			crossFileMsgSendTask.destroy();
			crossFileMsgSendTask = null;
		}
		
		if (msgResendTask != null) {
			msgResendTask.destroy();
			msgResendTask = null;
		}
		
		// 把缓存的内容保存到文件
		MtGroupTmpStore.lmtSmsSerialize();
		
		// 把缓存的内容保存到文件
		MtTmpStore.storeSerialize();
	}

	/**
	 * 启动短信发送服务
	 */
	protected static void startSendService() {
		
		if (client == null) {
			
			ClientMessageHandler clientMessageHandler = new ClientMessageHandler();
			
			switch(AppStaticConfigs.smsSourceType) {
			case DB:
				DbWriterDispatcher dbDdispatcher = new DbWriterDispatcher();
				clientMessageHandler.setWriter(dbDdispatcher);
				break;
			case FILE:
				FileWriterDispatcher fileDispatcher = new FileWriterDispatcher();
				if (AppStaticConfigs.isMultiAccount) {
					fileDispatcher.setMultiModel(true);
				} else {
					fileDispatcher.setMultiModel(false);
				}
				clientMessageHandler.setWriter(fileDispatcher);
				break;
			default:
				break;
		}
//			DbWriterDispatcher dispatcher = new DbWriterDispatcher();
//			if (AppStaticConfigs.isMultiAccount) {
//				dispatcher.setMultiModel(true);
//			} else {
//				dispatcher.setMultiModel(false);
//			}
//			clientMessageHandler.setWriter(dispatcher);
			
			client = new SmsClient();
			client.setSrvNode(AppStaticConfigs.srvNode);
			client.setServerIp(AppStaticConfigs.serverIp);
			client.setServerPort(AppStaticConfigs.serverPort);
			client.setLoginName(AppStaticConfigs.serverLoginName);
			client.setLoginPass(AppStaticConfigs.serverLoginPass);
			client.setMessageHandler(clientMessageHandler);
			client.setHandlerBound(true);
			client.setMaxSize(AppStaticConfigs.msgSendMaxSize);
		}
		
		if (tryStartSendTasks == null || !tryStartSendTasks.isAlive()) {
			
			tryStartSendTasks = new Thread(new Runnable() {
				
				@Override
				public void run() {
					
					boolean testBindable = client.testBindable();
					
					while (!testBindable && client != null) {
						
						try {
							TimeUnit.MILLISECONDS.sleep(10000);
						} catch (InterruptedException e) {
							break;
						}
						
						testBindable = client.testBindable();
						
						if (!testBindable) logger.warn("目标地址:" + client.getServerIp() + ":" + client.getServerPort() + "连接绑定失败!");
					}
					
					if (testBindable && client != null) {
						
						// 读取持久化的内容
						MtGroupTmpStore.lmtSmsDeSerialize();
						
						// 读取持久化的内容
						MtTmpStore.storeDeSerialize();
						
						// 短信发送任务
						switch(AppStaticConfigs.smsSourceType) {
							case DB:
								generateMsgSendTaskNew = new GenerateMsgSendTaskNew(client);
								generateMsgSendTaskNew.start();
								break;
							case FILE: 
								generateMsgSendTask = new GenerateMsgSendTask(client);
								generateMsgSendTask.start();
								break;
							default:
								break;
						}
						
						// 跨文件的长短信将在合并后通过该任务进行发送
						crossFileMsgSendTask = new CrossFileMsgSendTask(client);
						crossFileMsgSendTask.start();
						
						// 短信推送到平台后没有接收到响应消息,则会重新推送短信,直至推送成功或者推送次数达到三次后则认为短信发送失败
						msgResendTask = new MsgResendTask(client);
						msgResendTask.start();
						
					} else {
						if (listener != null) {
							listener.getHandler().stop(new String[]{});
						}
					}
				}
			});
			tryStartSendTasks.start();
		}
	}

	/**
	 * 启动端口监听服务
	 */
	public static void startService() {
		
		if (server == null) {
			
			ExtSocketManager socketManager = new ExtSocketManager();
			socketManager.setClearOutTimeSocketAutomatic(true);
			socketManager.setLimit(true);
			socketManager.setMaxSize(AppStaticConfigs.maxSocketSize);
			
			ServerMessageHandler serverMessageHandler = new ServerMessageHandler();
			switch(AppStaticConfigs.smsSourceType) {
				case DB:
					DbWriterDispatcher dbDdispatcher = new DbWriterDispatcher();
					serverMessageHandler.setWriter(dbDdispatcher);
					break;
				case FILE:
					FileWriterDispatcher fileDispatcher = new FileWriterDispatcher();
					if (AppStaticConfigs.isMultiAccount) {
						fileDispatcher.setMultiModel(true);
					} else {
						fileDispatcher.setMultiModel(false);
					}
					serverMessageHandler.setWriter(fileDispatcher);
					break;
				default:
					break;
			}
//			DbWriterDispatcher dispatcher = new DbWriterDispatcher();		
//			serverMessageHandler.setWriter(dispatcher);
			
			server = new SmsServer()
					.setPort(AppStaticConfigs.clientServerPort)
					.setValidator(new UserValidator(AppStaticConfigs.clientServerLoginName, AppStaticConfigs.clientServerLoginPass))
					.setSocketManager(socketManager)
					.setMessageHandler(serverMessageHandler);
			server.startService();
			
		} else {
			if (!server.isKeepGoing()) {
				server = null;
				startService();
			}
		}
	}

	/**
	 * 关闭端口监听服务
	 */
	public static void stopService() {

		if (server != null && server.isKeepGoing()) {
			server.stopService();
		}
		
		server = null;
	}
	
	public static void reloadConfigs() {
		
		AppStaticConfigs.reload();
		
		if (client != null) {
			client.setSrvNode(AppStaticConfigs.srvNode);
			client.setServerIp(AppStaticConfigs.serverIp);
			client.setServerPort(AppStaticConfigs.serverPort);
			client.setLoginName(AppStaticConfigs.serverLoginName);
			client.setLoginPass(AppStaticConfigs.serverLoginPass);
			client.setMaxSize(AppStaticConfigs.msgSendMaxSize);
		}
		
		if (server != null) {
			server.setPort(AppStaticConfigs.clientServerPort);
			server.setValidator(new UserValidator(AppStaticConfigs.clientServerLoginName, AppStaticConfigs.clientServerLoginPass));
		}
		
	}

}
